## 使用本地命令操作k8s集群
## kubectl apply/delete -f xxx.yaml 方式
## 需要运行后台的程序机器安装kubectl
## windows安装kubectl
## 下载https://dl.k8s.io/release/v1.21.0/bin/windows/amd64/kubectl.exe 加入环境变量PATH即可
## 使用choco安装： choco install kubernetes-cli
## kubectl version --client
## 自动补全：kubectl completion powershell | Out-String | Invoke-Expression
## 配置集群连接配置：cd ~ && mkdir .kube && cd .kube && vim config

import os
import re
import uuid
import subprocess
import threading
from utils.auth_manog import auth_manog_done
from batch_yaml import models
from django.db.models import Q
from django.shortcuts import render, HttpResponse
from k8sMp.settings import BASE_DIR
from django.http import JsonResponse
from k8sMp.settings import logger
from kubernetes import client, config, utils
from user_system.models import GameServerGroup

# 线程数
max_threads = 100

def get_k8s_api(request):
    project_id = request.session.get("project_id")
    user_id = request.session.get("user_id")
    setting_config = models.K8sConfig.objects.filter(project_id=project_id, user_id=user_id).first()
    if setting_config:
        config_content = setting_config.config_content
        k8s_config_dir = os.path.join(BASE_DIR, 'k8s', 'static', str(user_id), 'k8s_config')
        if not os.path.exists(k8s_config_dir): os.makedirs(k8s_config_dir)
        k8s_config_path = os.path.join(k8s_config_dir, 'k8s_config')
        with open(k8s_config_path, 'w') as f:
            f.write(config_content)
        config.kube_config.load_kube_config(config_file=k8s_config_path)
        # 管理deployment时使用
        my_AppsV1Api = client.AppsV1Api()
        # 查看资源/管理service时使用
        my_CoreV1Api = client.CoreV1Api()

        return my_AppsV1Api, my_CoreV1Api
    else:
        return None

def execute_cmd(server_cmd, uuid_str):
    """
    执行本地命令
    :param server_cmd:
    :param uuid_str:
    :return:
    """
    cmd_result = {}
    cmd_result["uuid_str"] = uuid_str
    # 被执行的脚本如果有长文本输出，应该加上  > /dev/null 2>&1 ，否则有可能卡死subprocess.Popen https://www.cnblogs.com/slqt/p/10362527.html
    # p = subprocess.Popen(server_cmd, shell=True, close_fds=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    p = subprocess.Popen(server_cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    while p.poll() is None:
        line = p.stdout.readline()
        line = line.strip()
        if line:
            logger.info("uuid: %s %s" % (uuid_str, line))
    if p.returncode == 0:
        logger.info("uuid: %s success" % uuid_str)
    else:
        logger.error("uuid: %s failed" % uuid_str)
    out, err = p.communicate()
    cmd_result["code"] = p.returncode
    if p.returncode != 0 and err:
        cmd_result["error"] = err
    else:
        cmd_result["error"] = None
    cmd_result["server_cmd"] = server_cmd
    return cmd_result

# 判断线程数
def judge_threads():
    while True:
        current_threads = threading.active_count()  # 获取当前线程数
        logger.info("current_threads: %s" % current_threads)
        if current_threads >= max_threads:
            pass
        else:
            break


@auth_manog_done
def SettingConfig(request):
    if request.method == "GET":
        project_id = request.session.get("project_id")
        if not project_id:
            return HttpResponse("没有选择项目，不可操作")
        project_id = request.session.get("project_id")
        user_id = request.session.get("user_id")
        setting_config_list = models.K8sConfig.objects.filter(project_id=project_id, user_id=user_id).all()
        return render(request, "k8s/setting_config.html", {"setting_config_list": setting_config_list})


@auth_manog_done
def SettingConfigAdd(request):
    project_id = request.session.get("project_id")
    user_id = request.session.get("user_id")
    if request.method == "GET":
        config_content_obj = models.K8sConfig.objects.filter(project_id=project_id, user_id=user_id).first()
        return render(request, "k8s/setting_config_add.html", {"config_content_obj": config_content_obj})
    if request.method == "POST":
        config_content = request.POST.get("config_content", None)
        if config_content:
            if not models.K8sConfig.objects.filter(project_id=project_id, user_id=user_id).all():
                models.K8sConfig.objects.create(project_id=project_id, user_id=user_id, config_content=config_content)
            else:
                models.K8sConfig.objects.filter(project_id=project_id, user_id=user_id).update(
                    config_content=config_content)

            # 将连接集群的配置文件配置到本机
            # os.path.expanduser('~') 获取家目录
            # 会导致只能连接操作一个集群
            kube_conf_dir = os.path.join(os.path.expanduser('~'), ".kube")
            if not os.path.exists(kube_conf_dir): os.makedirs(kube_conf_dir)
            kube_conf_path = os.path.join(kube_conf_dir, "config")
            with open(kube_conf_path, "w") as f:
                f.write(config_content)
        return HttpResponse("配置成功")


@auth_manog_done
def SettingConfigDetail(request, config_id):
    if request.method == "GET":
        project_id = request.session.get("project_id")
        user_id = request.session.get("user_id")
        config_content_obj = models.K8sConfig.objects.filter(id=config_id, project_id=project_id,
                                                             user_id=user_id).first()
        return render(request, "k8s/setting_config_detail.html", {"config_content_obj": config_content_obj})


@auth_manog_done
def NodesList(request):
    k8s_api = get_k8s_api(request)
    if k8s_api:
        my_CoreV1Api = k8s_api[1]
        nodes_list = my_CoreV1Api.list_node().items
    else:
        nodes_list = None
    return render(request, "k8s/nodes_list.html", {"nodes_list": nodes_list})


@auth_manog_done
def NamespaceList(request):
    k8s_api = get_k8s_api(request)
    if k8s_api:
        my_CoreV1Api = k8s_api[1]
        namespaces_list = my_CoreV1Api.list_namespace().items
    else:
        namespaces_list = None
    return render(request, "k8s/namespaces_list.html", {"namespaces_list": namespaces_list})


@auth_manog_done
def PodList(request):
    k8s_api = get_k8s_api(request)
    if k8s_api:
        try:
            my_CoreV1Api = k8s_api[1]
            pods_list = my_CoreV1Api.list_pod_for_all_namespaces().items
        except Exception as e:
            logger.error(e)
            logger.error('异常文件：%s ,异常行号：%s' % (e.__traceback__.tb_frame.f_globals['__file__'], e.__traceback__.tb_lineno))
    else:
        pods_list = None

    return render(request, "k8s/pods_list.html", {"pods_list": pods_list})


@auth_manog_done
def ServiceList(request):
    k8s_api = get_k8s_api(request)
    if k8s_api:
        my_CoreV1Api = k8s_api[1]
        service_list = my_CoreV1Api.list_service_for_all_namespaces().items
    else:
        service_list = None
    return render(request, "k8s/service_list.html", {"service_list": service_list})


@auth_manog_done
def YamlTemplateList(request):
    if request.method == "GET":
        project_id = request.session.get("project_id")
        template_list = models.K8sTemplateYaml.objects.filter(project_id=project_id).all()
        return render(request, "k8s/yaml_Template_list.html", {"template_list": template_list})


@auth_manog_done
def YamlTemplateDetail(request, template_id):
    if request.method == "GET":
        project_id = request.session.get("project_id")
        yaml_obj = models.K8sTemplateYaml.objects.filter(id=template_id, project_id=project_id).first()
        return render(request, "k8s/yaml_Template_detail.html", {"yaml_obj": yaml_obj})


def YamlTemplateOps(request, project_id):
    uuid_str = str(uuid.uuid1()).upper().replace('-', '')
    user_id = request.session.get("user_id")
    username = request.session.get("username")
    name = request.POST.get("name", None)
    content = request.POST.get("content", None)
    if name and content:
        if models.K8sTemplateYaml.objects.filter(project_id=project_id, name=name).first():
            yaml_obj = models.K8sTemplateYaml.objects.get(name=name)
            yaml_obj.name = name
            yaml_obj.content = content
            yaml_obj.save()
            message = {"code": 0, "msg": "server_id: %s，更新成功" % name}
        else:
            models.K8sTemplateYaml.objects.create(
                name=name,
                content=content,
                project_id=project_id
            )
            message = {"code": 0, "msg": "server_id: %s，添加成功" % name}
            models.TaskList.objects.create(user_id=user_id,
                                           project_id=project_id,
                                           uuid_str=uuid_str,
                                           name="添加yaml模板",
                                           op_task="add yaml template",
                                           status=2
                                           )
            logger.info("%s uuid: %s 添加yaml模板成功" % (username, uuid_str))
    else:
        message = {"code": 1, "msg": "内容没填写完整"}

    return message


@auth_manog_done
def YamlTemplateAdd(request):
    project_id = request.session.get("project_id")
    if request.method == "GET":
        return render(request, "k8s/yaml_Template_add.html")

    if request.method == "POST":
        try:
            message = YamlTemplateOps(request, project_id)
        except Exception as e:
            logger.error(e)
            logger.error(
                '异常文件：%s ,异常行号：%s' % (e.__traceback__.tb_frame.f_globals['__file__'], e.__traceback__.tb_lineno))
            message = {"code": 1, "msg": "异常%s" % e}

        return JsonResponse(message)


def write_yaml_to_file(yaml_file_path, yaml_content):
    """将yaml内容写入文件并拿到特定的字段值"""
    with open(yaml_file_path, 'w') as f:
        f.write(yaml_content)
    # 读取yaml文件获取namespace和deployment_name
    with open(yaml_file_path, 'r') as f:
        for i in range(15):
            line = f.readline()
            if "namespace:" in line:
                namespace = line.split(':')[1].strip()
            if "name:" in line:
                deployment_name = line.split(':')[1].strip()
            if "replicas:" in line:
                replicas = line.split(':')[1].strip()
    # 获取nodePort
    nodePort_list = []
    with open(yaml_file_path, 'r') as f:
        line_list = f.readlines()
        for line in line_list:
            if "nodePort:" in line:
                nodePort = line.split(':')[1].strip()
                nodePort_list.append(nodePort)
    return namespace, deployment_name, replicas, nodePort_list


def add_new_port(project_id, num_list, yaml_content):
    """
    生成新的未使用端口
    :return:
    """
    # 获取已经占用的端口
    nodePort_list_all = []
    yaml_obj_list = models.K8sYaml.objects.filter(project_id=project_id).all()
    for yaml_obj in yaml_obj_list:
        nodePort_list = eval(yaml_obj.nodePort_list)
        # 合并列表
        nodePort_list_all = nodePort_list_all + nodePort_list
    # 制造端口号
    num_len = len(num_list)
    port_list_all = range(30000, 50000)
    port_list = []
    count = 0
    for port in port_list_all:
        port = str(port)
        if count < num_len:
            if port not in nodePort_list_all:
                port = int(port)
                port_list.append(port)
                count += 1
        else:
            break
    # 替换端口号
    for (num, port) in zip(num_list, port_list):
        yaml_content = yaml_content.replace(num, str(port))
    logger.info("新分配得到的端口号，%s" % port_list)
    return yaml_content

def generate_port_rules(template_content, server_id, yaml_obj, project_id):
    """
    生成端口规则
    :return:
    """
    yaml_content = template_content.replace("9999", server_id)
    num_list = ["aaaa", "bbbb", "cccc", "dddd", "eeee", "ffff", "gggg", "hhhh", "iiii"]

    # 已经分配有端口了的
    if yaml_obj:
        nodePort_list = yaml_obj.nodePort_list

        # 替换原有端口
        port_list = eval(nodePort_list)
        for (num, port) in zip(num_list, port_list):
            yaml_content = yaml_content.replace(num, str(port))
        logger.info("原有已分配好的端口号，%s" % port_list)
        # 判断修改模板时可能有新增的端口
        temp_num_list = []
        for num in num_list:
            if num in yaml_content:
                temp_num_list.append(num)
        if temp_num_list:
            logger.info("修改模板时新增了端口")
            yaml_content = add_new_port(project_id, num_list, yaml_content)

    else:
        # 获取已经占用的端口
        yaml_content = add_new_port(project_id, num_list, yaml_content)
    return yaml_content


@auth_manog_done
def YamlTemplateEdit(request, template_id):
    project_id = request.session.get("project_id")
    uuid_str = str(uuid.uuid1()).upper().replace('-', '')
    user_id = request.session.get("user_id")
    username = request.session.get("username")
    if request.method == "GET":
        yaml_obj = models.K8sTemplateYaml.objects.filter(id=template_id, project_id=project_id).first()
        return render(request, "k8s/yaml_Template_edit.html", {"yaml_obj": yaml_obj})

    if request.method == "POST":
        try:
            name = request.POST.get("name", None)
            template_content = request.POST.get("content", None)
            if name and template_content:
                if models.K8sTemplateYaml.objects.filter(project_id=project_id, id=template_id).first():
                    # 更新模板内容信息
                    template_yaml_obj = models.K8sTemplateYaml.objects.get(project_id=project_id, id=template_id)
                    template_yaml_obj.name = name
                    template_yaml_obj.content = template_content

                    # 同步使用该模板的yaml
                    yaml_list = models.K8sYaml.objects.filter(project_id=project_id, template_id=template_id).all()
                    for yaml_obj in yaml_list:
                        server_id = str(yaml_obj.server_id)

                        # 根据变量规则和yaml模板生成yaml
                        yaml_content = generate_port_rules(template_content, server_id, yaml_obj, project_id)

                        # 更新yaml到数据库
                        yaml_obj_new = models.K8sYaml.objects.get(project_id=project_id, server_id=server_id)
                        yaml_obj_new.yaml_content = yaml_content

                        # 写到yaml文件
                        yaml_file_dir = os.path.join(BASE_DIR, "k8s", "static", "yaml")
                        if not os.path.exists(yaml_file_dir): os.makedirs(yaml_file_dir)
                        yaml_filename = yaml_obj_new.yaml_name
                        yaml_file_path = os.path.join(yaml_file_dir, yaml_filename)

                        yaml_info = write_yaml_to_file(yaml_file_path, yaml_content)

                        yaml_obj_new.namespace = yaml_info[0]  # namespace
                        yaml_obj_new.deployment_name = yaml_info[1]  # deployment_name
                        yaml_obj_new.replicas = yaml_info[2]  # replicas
                        yaml_obj_new.nodePort_list = yaml_info[3]# nodePort_list
                        yaml_obj_new.save()
                        logger.info("%s uuid: %s 修改yaml模板 template_id: %s, server_id: %s 同步模板成功" % (username, uuid_str, template_id, server_id))

                    # 成功同步到使用改模板的yaml后，再保存模板内容
                    template_yaml_obj.save()
                    models.TaskList.objects.create(user_id=user_id,
                                                   project_id=project_id,
                                                   uuid_str=uuid_str,
                                                   name="修改yaml模板",
                                                   op_task="update yaml template",
                                                   status=2,
                                                   success_result=template_id
                                                   )
                    message = {"code": 0, "msg": "模板: 【%s】，修改成功 并 同步更新到使用该模板的yaml成功" % name}
                else:
                    message = {"code": 1, "msg": "没有这个模板【%s】" % name}
            else:
                message = {"code": 1, "msg": "内容没填写完整"}
        except Exception as e:
            logger.error(e)
            logger.error(
                '异常文件：%s ,异常行号：%s' % (e.__traceback__.tb_frame.f_globals['__file__'], e.__traceback__.tb_lineno))
            message = {"code": 1, "msg": "异常%s" % e}
        return JsonResponse(message)


@auth_manog_done
def YamlList(request):
    project_id = request.session.get("project_id")
    group_list = GameServerGroup.objects.filter(b_project_id=project_id).all()
    script_type_list = [
        ["deploy", "部署"],
        ["update", "更新"],
        ["stop", "停服"],
        ["start", "启动"],
        ["delete", "删除"],
        ["restart", "重启"],
        ["backup_mongodb", "备份mongodb"],
        ["backup_redis", "备份redis"],
        ["backup_mysql", "备份mysql"],
        ["clear", "清档"]
    ]

    if request.method == "GET":

        k8s_api = get_k8s_api(request)
        if k8s_api:
            my_CoreV1Api = k8s_api[1]
            exclude_namespaces_list = ["default", "ingress-nginx", "kruise-system", "kube-node-lease",
                                       "kube-public", "kube-system", "kuboard"]
            namespaces_list = my_CoreV1Api.list_namespace().items
            for namespaces in namespaces_list:
                namespaces_name = namespaces.metadata.name
                if namespaces_name not in exclude_namespaces_list:
                    namespaces_pods_list = my_CoreV1Api.list_namespaced_pod(namespaces_name).items
                    for namespaces_pods in namespaces_pods_list:
                        for pod_info in namespaces_pods.status.container_statuses:
                            ready_status = pod_info.ready
                            if not ready_status:
                                status = "Not Ready"
                                break
                            else:
                                status = "Running"
                        labels = namespaces_pods.metadata.labels
                        if 'app' in labels.keys():
                            deployment_name = labels["app"]
                            print(deployment_name)
                            pod_ip = namespaces_pods.status.pod_ip
                            if models.K8sYaml.objects.filter(project_id=project_id, deployment_name=deployment_name):
                                yaml_obj = models.K8sYaml.objects.get(project_id=project_id, deployment_name=deployment_name)
                                yaml_obj.pod_ip = pod_ip
                                yaml_obj.status = status
                                yaml_obj.save()

        yaml_list = models.K8sYaml.objects.filter(project_id=project_id).all().order_by('-server_id')
        select_group_name = "选择分区"
        yaml_filter = ''
        return render(request, "k8s/yaml_list.html", {
            "yaml_list": yaml_list,
            "group_list": group_list,
            "select_group_name": select_group_name,
            "yaml_filter": yaml_filter,
            "script_type_list": script_type_list
        })

    if request.method == "POST":
        group_id = request.POST.get("group_id", None)
        yaml_filter = request.POST.get("yaml_filter", None)
        if group_id:
            yaml_list = models.K8sYaml.objects.filter(project_id=project_id, group_id=group_id).all().order_by('-server_id')
            select_group_name = models.GameServerGroup.objects.filter(b_project_id=project_id,id=group_id).first().group_name
            yaml_filter = ''

        elif yaml_filter:
            yaml_filter = yaml_filter.strip()
            yaml_list = models.K8sYaml.objects.filter(project_id=project_id).filter(
                Q(server_id__contains=yaml_filter) |
                Q(server_name__contains=yaml_filter) |
                Q(namespace__contains=yaml_filter) |
                Q(yaml_name__contains=yaml_filter)
            ).order_by("-server_id")
            select_group_name = "选择分区"
        else:
            yaml_list = models.K8sYaml.objects.filter(project_id=project_id).all().order_by('-server_id')
            select_group_name = "选择分区"
            yaml_filter = ''

        return render(request, "k8s/yaml_list.html", {
            "yaml_list": yaml_list,
            "group_list": group_list,
            "select_group_name": select_group_name,
            "yaml_filter": yaml_filter,
            "script_type_list": script_type_list
        })


@auth_manog_done
def YamlDetail(request, yaml_id):
    if request.method == "GET":
        project_id = request.session.get("project_id")
        yaml_obj = models.K8sYaml.objects.filter(id=yaml_id, project_id=project_id).first()
        return render(request, "k8s/yaml_detail.html", {"yaml_obj": yaml_obj})


def YamlOps_add(request, project_id):
    server_id = request.POST.get("server_id", None)
    server_name = request.POST.get("server_name", None)
    template_id = request.POST.get("template_id", None)
    group_id = request.POST.get("group_id", None)
    uuid_str = str(uuid.uuid1()).upper().replace('-', '')
    user_id = request.session.get("user_id")
    username = request.session.get("username")

    if server_id and server_name and template_id and group_id:
        template_obj = models.K8sTemplateYaml.objects.filter(project_id=project_id, id=template_id).first()
        template_content = template_obj.content
        yaml_name = 'yaml_%s_%s.yaml' % (project_id, server_id)

        # 根据变量规则和yaml模板生成yaml
        yaml_obj = None
        yaml_content = generate_port_rules(template_content, server_id, yaml_obj, project_id)

        if not models.K8sYaml.objects.filter(project_id=project_id, server_id=server_id).first():
            yaml_file_dir = os.path.join(BASE_DIR, "k8s", "static", "yaml")
            if not os.path.exists(yaml_file_dir): os.makedirs(yaml_file_dir)
            yaml_file_path = os.path.join(yaml_file_dir, yaml_name)

            yaml_info = write_yaml_to_file(yaml_file_path, yaml_content)

            models.K8sYaml.objects.create(
                yaml_name=yaml_name,
                server_id=server_id,
                namespace=yaml_info[0],         # namespace
                deployment_name=yaml_info[1],   # deployment_name
                replicas=yaml_info[2],          # replicas
                nodePort_list=yaml_info[3],     # nodePort_list
                server_name=server_name,
                yaml_content=yaml_content,
                project_id=project_id,
                template_id=template_id,
                group_id=group_id
            )
            message = {"code": 0, "msg": "server_id: %s，添加成功" % server_id}
            models.TaskList.objects.create(user_id=user_id,
                                           project_id=project_id,
                                           uuid_str=uuid_str,
                                           name="增加yaml文件 %s" % yaml_name,
                                           op_task="add yaml file",
                                           status=2,
                                           success_result=server_id
                                           )
            logger.info("%s uuid: %s 添加yaml文件 %s 成功" % (username, uuid_str, yaml_name))
        else:
            message = {"code": 1, "msg": "server_id已存在，不可重复添加"}
    else:
        message = {"code": 1, "msg": "内容没填写完整"}

    return message


@auth_manog_done
def YamlAdd(request):
    project_id = request.session.get("project_id")
    if request.method == "GET":
        template_list = models.K8sTemplateYaml.objects.filter(project_id=project_id).all()
        group_list = GameServerGroup.objects.filter(b_project_id=project_id).all()
        return render(request, "k8s/yaml_add.html", {"template_list": template_list, "group_list": group_list})

    if request.method == "POST":
        try:
            message = YamlOps_add(request, project_id)
        except Exception as e:
            logger.error(e)
            logger.error(
                '异常文件：%s ,异常行号：%s' % (e.__traceback__.tb_frame.f_globals['__file__'], e.__traceback__.tb_lineno))
            message = {"code": 1, "msg": "异常%s" % e}
        return JsonResponse(message)


@auth_manog_done
def YamlEdit(request, yaml_id):
    project_id = request.session.get("project_id")
    uuid_str = str(uuid.uuid1()).upper().replace('-', '')
    user_id = request.session.get("user_id")
    username = request.session.get("username")
    if request.method == "GET":
        yaml_obj = models.K8sYaml.objects.filter(id=yaml_id, project_id=project_id).first()
        group_id = yaml_obj.group_id
        current_group_obj = models.GameServerGroup.objects.filter(b_project=project_id, id=group_id).first()
        group_list = models.GameServerGroup.objects.filter(b_project_id=project_id).all()
        return render(request, "k8s/yaml_edit.html",
                      {"yaml_obj": yaml_obj, "group_list": group_list, "current_group_obj": current_group_obj})

    if request.method == "POST":
        try:
            server_id = request.POST.get("server_id", None)
            server_name = request.POST.get("server_name", None)
            yaml_content = request.POST.get("yaml_content", None)
            group_id = request.POST.get("group_id", None)
            deploy_status = request.POST.get("deploy_status", None)
            if server_id and server_name and yaml_content and group_id and deploy_status:
                yaml_obj = models.K8sYaml.objects.get(project_id=project_id, server_id=server_id)
                yaml_obj.server_id = server_id
                yaml_obj.server_name = server_name
                yaml_obj.yaml_content = yaml_content
                yaml_obj.group_id = group_id
                yaml_obj.deploy_status = deploy_status

                # 编辑后写到文件
                yaml_name = yaml_obj.yaml_name
                yaml_file_dir = os.path.join(BASE_DIR, "k8s", "static", "yaml")
                if not os.path.exists(yaml_file_dir): os.makedirs(yaml_file_dir)
                yaml_file_path = os.path.join(yaml_file_dir, yaml_name)
                with open(yaml_file_path, 'w') as f:
                    f.write(yaml_content)

                yaml_info = write_yaml_to_file(yaml_file_path, yaml_content)

                yaml_obj.namespace = yaml_info[0]  # namespace
                yaml_obj.deployment_name = yaml_info[1]  # deployment_name
                yaml_obj.replicas = yaml_info[2]  # replicas
                yaml_obj.nodePort_list = yaml_info[3]  # nodePort_list

                yaml_obj.save()
                models.TaskList.objects.create(user_id=user_id,
                                               project_id=project_id,
                                               uuid_str=uuid_str,
                                               name="编辑yaml文件 %s" % yaml_name,
                                               op_task="edit yaml file",
                                               status=2,
                                               success_result=server_id
                                               )
                logger.info("%s uuid: %s 编辑yaml文件 %s 成功" % (username, uuid_str, yaml_name))
                message = {"code": 0, "msg": "server_id: %s，修改成功" % server_id}
            else:
                message = {"code": 1, "msg": "server_id: %s，修改失败，内容不完整" % server_id}
        except Exception as e:
            logger.error(e)
            logger.error(
                '异常文件：%s ,异常行号：%s' % (e.__traceback__.tb_frame.f_globals['__file__'], e.__traceback__.tb_lineno))
            message = {"code": 1, "msg": "异常%s" % e}
        return JsonResponse(message)


# 部署yaml
def deploy(yaml_obj, project_id, user_id):
    deploy_status = yaml_obj.deploy_status
    uuid_str = str(uuid.uuid1()).upper().replace('-', '')
    yaml_name = yaml_obj.yaml_name
    server_id = yaml_obj.server_id
    if deploy_status == 1:  # 未部署
        yaml_file_dir = os.path.join(BASE_DIR, "k8s", "static", "yaml")
        if not os.path.exists(yaml_file_dir): os.makedirs(yaml_file_dir)
        yaml_filename = yaml_obj.yaml_name
        yaml_file_path = os.path.join(yaml_file_dir, yaml_filename)
        server_cmd = "kubectl apply -f %s" % yaml_file_path
        cmd_result = execute_cmd(server_cmd, uuid_str)
        if cmd_result["code"] == 0:
            yaml_obj.deploy_status = 2
            yaml_obj.save()
            models.TaskList.objects.create(user_id=user_id,
                                           project_id=project_id,
                                           uuid_str=uuid_str,
                                           name="部署yaml资源 %s" % yaml_name,
                                           op_task="deploy yaml",
                                           status=2,
                                           success_result=server_id
                                           )
            logger.info("%s uuid: %s 部署yaml资源 %s 成功" % (user_id, uuid_str, yaml_name))
            message = {"code": 0, "msg": "部署yaml资源成功"}
        else:
            error = cmd_result["error"]
            message = {"code": 1, "msg": "部署yaml资源失败，Error: %s" % error}
    else:
        message = {"code": 1, "msg": "已部署，不可重复部署"}
    return message


@auth_manog_done
def YamlApply(request):
    project_id = request.session.get("project_id")
    user_id = request.session.get("user_id")
    if request.method == "POST":
        try:
            server_id = request.POST.get("server_id", None)
            yaml_obj = models.K8sYaml.objects.get(project_id=project_id, server_id=server_id)
            message = deploy(yaml_obj, project_id, user_id)
        except Exception as e:
            logger.error(e)
            logger.error(
                '异常文件：%s ,异常行号：%s' % (e.__traceback__.tb_frame.f_globals['__file__'], e.__traceback__.tb_lineno))
            message = {"code": 1, "msg": "apply Failed. ERROR: %s" % e}
        logger.info(message)
        return JsonResponse(message, json_dumps_params={"ensure_ascii": False, "sort_keys": True, "indent": 4})


# 更新yaml
def update(request, yaml_obj):
    try:
        project_id = request.session.get("project_id")
        user_id = request.session.get("user_id")
        username = request.session.get("username")
        deploy_status = yaml_obj.deploy_status
        uuid_str = str(uuid.uuid1()).upper().replace('-', '')
        server_id = yaml_obj.server_id
        if deploy_status == 2:
            yaml_name = yaml_obj.yaml_name
            yaml_file_dir = os.path.join(BASE_DIR, "k8s", "static", "yaml")
            if not os.path.exists(yaml_file_dir): os.makedirs(yaml_file_dir)
            yaml_file_path = os.path.join(yaml_file_dir, yaml_name)
            server_cmd = "kubectl apply -f %s" % yaml_file_path
            cmd_result = execute_cmd(server_cmd, uuid_str)
            if cmd_result["code"] == 0:
                message = {"code": 0, "msg": "更新成功"}
                models.TaskList.objects.create(user_id=user_id,
                                               project_id=project_id,
                                               uuid_str=uuid_str,
                                               name="更新yaml文件 %s" % yaml_name,
                                               op_task="update yaml",
                                               status=2,
                                               success_result=server_id
                                               )
                logger.info("%s uuid: %s 更新yaml文件 %s 成功" % (username, uuid_str, yaml_name))
            else:
                error = cmd_result["error"]
                message = {"code": 1, "msg": "更新失败，Error: %s" % error}
                models.TaskList.objects.create(user_id=user_id,
                                               project_id=project_id,
                                               uuid_str=uuid_str,
                                               name="更新%s" % yaml_name,
                                               op_task="update yaml",
                                               status=3,
                                               fail_result=server_id,
                                               exception_message="更新失败，Error: %s" % error
                                               )
                logger.info("%s uuid: %s 更新yaml文件 %s 失败, Error: %s" % (username, uuid_str, yaml_name, message))
        else:
            message = {"code": 1, "msg": "未部署，不可操作更新"}
    except Exception as e:
        logger.error(e)
        logger.error('异常文件：%s ,异常行号：%s' % (e.__traceback__.tb_frame.f_globals['__file__'], e.__traceback__.tb_lineno))
        message = {"code": 1, "msg": "更新失败. ERROR: %s" % e}
    return message


@auth_manog_done
def YamlUpdate(request):
    project_id = request.session.get("project_id")
    if request.method == "POST":
        try:
            server_id = request.POST.get("server_id", None)
            yaml_obj = models.K8sYaml.objects.filter(project_id=project_id, server_id=server_id).first()
            print(yaml_obj)
            message = update(request, yaml_obj)
        except Exception as e:
            logger.error(e)
            logger.error(
                '异常文件：%s ,异常行号：%s' % (e.__traceback__.tb_frame.f_globals['__file__'], e.__traceback__.tb_lineno))
            message = {"code": 1, "msg": "更新失败. ERROR: %s" % e}
        logger.info(message)
        return JsonResponse(message, json_dumps_params={"ensure_ascii": False, "sort_keys": True, "indent": 4})


# 删除yaml的部署
def delete(request, yaml_obj):
    project_id = request.session.get("project_id")
    user_id = request.session.get("user_id")
    username = request.session.get("username")
    yaml_name = yaml_obj.yaml_name
    server_id = yaml_obj.server_id
    uuid_str = str(uuid.uuid1()).upper().replace('-', '')
    deploy_status = yaml_obj.deploy_status
    if deploy_status == 1:
        message = {"code": 1, "msg": "yaml资源不存在，无法删除"}
        models.TaskList.objects.create(user_id=user_id,
                                       project_id=project_id,
                                       uuid_str=uuid_str,
                                       name="删除yaml资源 %s" % yaml_name,
                                       op_task="delete yaml",
                                       status=3,
                                       fail_result=server_id,
                                       exception_message=message
                                       )
        logger.info("%s uuid: %s 删除yaml资源 %s 失败，yaml资源不存在，无法删除" % (username, uuid_str, yaml_name))
    else:
        yaml_file_dir = os.path.join(BASE_DIR, "k8s", "static", "yaml")
        if not os.path.exists(yaml_file_dir): os.makedirs(yaml_file_dir)
        yaml_file_path = os.path.join(yaml_file_dir, yaml_name)
        server_cmd = "kubectl delete -f %s" % yaml_file_path
        cmd_result = execute_cmd(server_cmd, uuid_str)
        if cmd_result["code"] == 0:
            yaml_obj.deploy_status = 1
            yaml_obj.pod_ip = None
            yaml_obj.save()
            message = {"code": 0, "msg": "删除yaml资源成功"}
            models.TaskList.objects.create(user_id=user_id,
                                           project_id=project_id,
                                           uuid_str=uuid_str,
                                           name="删除yaml资源 %s" % yaml_name,
                                           op_task="delete yaml",
                                           status=2,
                                           success_result=server_id
                                           )
            logger.info("%s uuid: %s 删除yaml资源 %s 成功" % (username, uuid_str, yaml_name))
        else:
            error = cmd_result["error"]
            message = {"code": 1, "msg": "删除yaml资源失败，%s" % error}
            models.TaskList.objects.create(user_id=user_id,
                                           project_id=project_id,
                                           uuid_str=uuid_str,
                                           name="删除yaml资源 %s" % yaml_name,
                                           op_task="delete yaml",
                                           status=3,
                                           fail_result=server_id,
                                           exception_message="删除yaml资源失败，%s" % error
                                           )
            logger.info("%s uuid: %s 删除yaml资源 %s 失败, Error: %s" % (username, uuid_str, yaml_name, message))
    return message


@auth_manog_done
def YamlDelete(request):
    project_id = request.session.get("project_id")
    if request.method == "POST":
        try:
            server_id = request.POST.get("server_id", None)
            yaml_obj = models.K8sYaml.objects.get(project_id=project_id, server_id=server_id)
            message = delete(request, yaml_obj)
        except Exception as e:
            logger.error(e)
            logger.error(
                '异常文件：%s ,异常行号：%s' % (e.__traceback__.tb_frame.f_globals['__file__'], e.__traceback__.tb_lineno))
            message = {"code": 1, "msg": "delete Failed", "error": e}
        logger.info(message)
        return JsonResponse(message, json_dumps_params={"ensure_ascii": False, "sort_keys": True, "indent": 4})


# 启动/停止yaml
def ops(request, yaml_obj, ops_type):
    project_id = request.session.get("project_id")
    user_id = request.session.get("user_id")
    username = request.session.get("username")
    uuid_str = str(uuid.uuid1()).upper().replace('-', '')
    deploy_status = yaml_obj.deploy_status
    yaml_name = yaml_obj.yaml_name
    server_id = yaml_obj.server_id
    replicas = yaml_obj.replicas
    yaml_content = yaml_obj.yaml_content
    message = None
    if deploy_status == 1:
        message = {"code": 1, "msg": "未部署，不可操作"}
    else:
        yaml_file_dir = os.path.join(BASE_DIR, "k8s", "static", "yaml")
        if not os.path.exists(yaml_file_dir): os.makedirs(yaml_file_dir)
        yaml_file_path = os.path.join(yaml_file_dir, yaml_name)

        if ops_type == "stop":
            # 修改replicas
            yaml_content = yaml_content.replace("replicas: %s" % replicas, "replicas: 0")
            with open(yaml_file_path, "w") as f:
                f.write(yaml_content)
            server_cmd = "kubectl apply -f %s" % yaml_file_path
            cmd_result = execute_cmd(server_cmd, uuid_str)
            if cmd_result["code"] == 0:
                yaml_obj.deploy_status = 3  # 已停止
                yaml_obj.status = "Stop"
                message = {"code": 0, "msg": "停止yaml资源成功"}
                models.TaskList.objects.create(user_id=user_id,
                                               project_id=project_id,
                                               uuid_str=uuid_str,
                                               name="停止yaml资源 %s" % yaml_name,
                                               op_task="stop yaml",
                                               status=2,
                                               success_result=server_id
                                               )
                logger.info("%s uuid: %s 停止yaml资源 %s 成功" % (username, uuid_str, yaml_name))
            else:
                error = cmd_result["error"]
                message = {"code": 1, "msg": "停止yaml资源失败，%s" % error}
                logger.info("%s uuid: %s 停止yaml资源 %s 失败 %s" % (username, uuid_str, yaml_name, error))
        if ops_type == "start":
            # 修改replicas
            yaml_content = yaml_content.replace("replicas: 0", "replicas: %s" % replicas)
            with open(yaml_file_path, "w") as f:
                f.write(yaml_content)
            server_cmd = "kubectl apply -f %s" % yaml_file_path
            cmd_result = execute_cmd(server_cmd, uuid_str)
            if cmd_result["code"] == 0:
                yaml_obj.deploy_status = 2  # 已部署
                message = {"code": 0, "msg": "启动yaml资源成功"}
                models.TaskList.objects.create(user_id=user_id,
                                               project_id=project_id,
                                               uuid_str=uuid_str,
                                               name="启动yaml资源 %s" % yaml_name,
                                               op_task="start yaml",
                                               status=2,
                                               success_result=server_id
                                               )
                logger.info("%s uuid: %s 启动yaml资源 %s 成功" % (username, uuid_str, yaml_name))
            else:
                error = cmd_result["error"]
                message = {"code": 1, "msg": "启动yaml资源失败，%s" % error}
                logger.info("%s uuid: %s 启动yaml资源 %s 失败 %s" % (username, uuid_str, yaml_name, error))
        yaml_obj.save()
    return message


@auth_manog_done
def YamlOps(request):
    project_id = request.session.get("project_id")
    if request.method == "POST":
        try:
            server_id = request.POST.get("server_id", None)
            ops_type = request.POST.get("ops_type", None)
            yaml_obj = models.K8sYaml.objects.get(project_id=project_id, server_id=server_id)
            message = ops(request, yaml_obj, ops_type)
        except Exception as e:
            logger.error(e)
            logger.error(
                '异常文件：%s ,异常行号：%s' % (e.__traceback__.tb_frame.f_globals['__file__'], e.__traceback__.tb_lineno))
            message = {"code": 1, "msg": "操作失败，Error: %s" % e}
        logger.info(message)
        return JsonResponse(message, json_dumps_params={"ensure_ascii": False, "sort_keys": True, "indent": 4})


@auth_manog_done
def YamlBatchOps(request):
    """
    yaml批量操作
    :param request:
    :return:
    """
    project_id = request.session.get("project_id")
    user_id = request.session.get("user_id")
    if request.method == "POST":
        try:
            yaml_id_list = request.POST.get("yaml_id", None)  # 前端传过来的全是字符串
            script_type = request.POST.get("script_type", None)
            if yaml_id_list and script_type:
                nums = re.findall(r'\d+', yaml_id_list)  # 匹配yaml_id组成数组
            else:
                message = {"code": 1, "msg": "操作错误，未选中操作项或操作对象"}
                return JsonResponse(message, json_dumps_params={"ensure_ascii": False, "sort_keys": True, "indent": 4})

            if isinstance(nums, list):  # 判断yaml_id是不是一个list
                task_obj = []
                logger.info("批量操作的server_id: %s" % nums)
                for yaml_id in nums:
                    yaml_obj = models.K8sYaml.objects.get(project_id=project_id, id=yaml_id)
                    server_id = yaml_obj.server_id
                    server_name = yaml_obj.server_name
                    logger.info("开始 %s server_id: %s, server_name: %s" % (script_type, server_id, server_name))

                    # 部署
                    if script_type == "deploy":
                        # deploy(yaml_obj, project_id, user_id)
                        t1 = threading.Thread(target=deploy, args=(yaml_obj, project_id, user_id))
                        t1.start()
                        task_obj.append(t1)
                        # 判断线程数
                        judge_threads()
                    # 更新
                    elif script_type == "update":
                        # update(request, yaml_obj)
                        t1 = threading.Thread(target=update, args=(request, yaml_obj))
                        t1.start()
                        task_obj.append(t1)
                        # 判断线程数
                        judge_threads()
                    # 停止
                    elif script_type == "stop":
                        # ops(request, yaml_obj, script_type)
                        t1 = threading.Thread(target=ops, args=(request, yaml_obj, script_type))
                        t1.start()
                        task_obj.append(t1)
                        # 判断线程数
                        judge_threads()
                    # 启动
                    elif script_type == "start":
                        # ops(request, yaml_obj, script_type)
                        t1 = threading.Thread(target=ops, args=(request, yaml_obj, script_type))
                        t1.start()
                        task_obj.append(t1)
                        # 判断线程数
                        judge_threads()
                    # 删除
                    elif script_type == "delete":
                        # delete(request, yaml_obj)
                        t1 = threading.Thread(target=delete, args=(request, yaml_obj))
                        t1.start()
                        task_obj.append(t1)
                        # 判断线程数
                        judge_threads()
                for t1 in task_obj:
                    t1.join()

                message = {"code": 0, "msg": "批量操作完成，可到任务管理查看各个任务操作状态"}
            else:
                message = {"code": 1, "msg": "操作错误，未选中操作对象"}
                return JsonResponse(message, json_dumps_params={"ensure_ascii": False, "sort_keys": True, "indent": 4})
        except Exception as e:
            logger.error(e)
            logger.error(
                '异常文件：%s ,异常行号：%s' % (e.__traceback__.tb_frame.f_globals['__file__'], e.__traceback__.tb_lineno))
            message = {"code": 1, "msg": "操作失败，Error: %s" % e}
        logger.info(message)
        return JsonResponse(message, json_dumps_params={"ensure_ascii": False, "sort_keys": True, "indent": 4})
